package com.fjbdxk.beidou;

import com.fjbdxk.beidou.msg.BDFKIMessage;
import com.fjbdxk.beidou.msg.CCTCQMessage;
import com.fjbdxk.beidou.net.SocketBeiDouNet;
import com.fjbdxk.beidou.redis.RedisUtil;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
 * 发送示例
 *
 * @author huanggy
 * @version 1.0.0
 * @date 2024/05/13
 **/
public class SendExampleTest {

    private static int totalNum = 9;

    private static int startNum = 1;

    private static final Logger LOGGER = Logger.getLogger(SendExample.class.getName());

    public static void main(String[] args) throws InterruptedException {
        // 使用网口通信
        SocketBeiDouNet socketBeiDouNet = new SocketBeiDouNet();
        socketBeiDouNet.open();//打开网络通信

        sendFile1(socketBeiDouNet);

    }

    public static String hexToBinary(String hexString) {
        // 将十六进制字符串转换为 BigInteger
        BigInteger bigInt = new BigInteger(hexString, 16);

        // 计算二进制字符串应有的长度（每个十六进制字符对应4位二进制）
        int numBinaryDigits = hexString.length() * 4;

        // 将 BigInteger 转换为二进制字符串，并补齐前导零
        String binaryString = bigInt.toString(2);
        while (binaryString.length() < numBinaryDigits) {
            binaryString = "0" + binaryString;
        }

        return binaryString;
    }


    public static String longBinaryToHex(String binaryString) {
        // 将二进制字符串转换为 BigInteger（大整数）
        BigInteger binaryBigInt = new BigInteger(binaryString, 2);

        // 将 BigInteger 转换为十六进制字符串
        String hexString = binaryBigInt.toString(16).toUpperCase(); // 转换为大写十六进制表示

        // 补齐前导零
        int numHexChars = (int) Math.ceil(binaryString.length() / 4.0); // 每4位二进制对应1位十六进制
        hexString = String.format("%" + numHexChars + "s", hexString).replace(' ', '0');

        return hexString;
    }


    private static void sendFile1(SocketBeiDouNet socketBeiDouNet) throws InterruptedException {
        while (true) {
            String dataByRedis = getDataByRedis();  // 从Redis获取数据
            System.out.println("分段发送的值未转换前为：" + dataByRedis);  // 打印未转换前的数据值
            String s = longBinaryToHex(dataByRedis);  // 将获取的数据转换成十六进制字符串

            // 打印转换后的数据值
            System.out.println("分段发送的值为：" + s);
            // 创建CCTCQMessage对象
            CCTCQMessage msg = new CCTCQMessage(15950114, s);  // 创建CCTCQMessage对象，包括数据和消息号
            msg.setEncodeType(2);  // 设置消息的编码类型为2
            System.out.println(msg.getMsg());  // 打印消息内容
            // 发送消息并接收响应
            BDFKIMessage res = (BDFKIMessage) socketBeiDouNet.sendMessage(msg);  // 向Socket发送消息并接收响应
            // 打印响应信息，如果响应为null则打印"N"，否则打印响应结果和失败结果
            System.out.println(res == null ? "N" : (res.getResult() + ":" + res.getFailResult()));
            Thread.sleep(60000);  // 线程休眠55秒
        }
    }



    public static String getDataByRedis() {

        String[] head = new String[]{"PLC状态", "环境温度", "风速", "功率", "转矩", "发电机转速", "叶轮转速", "风向", "桨距角", "发电量"};//csv文件的列头

        List<String[]> data1 = getRedisByKeyNew();
        String r = "";
        for (String[] data : data1) {


            for (int j = 0; j < data.length; j++) {//遍历每个字段
                String t1 = head[j];// 获取列头
                String t2 = data[j];//获取字段值
                switch (t1) {// 根据列头进行数据处理
                    case "PLC状态":
                        t2 = validateAndSendData(t1, t2, 1.0, 0, 70, 8);
                        break;
                    case "环境温度":
                        t2 = validateAndSendData(t1, t2, 1.0, -50, 50, 8);
                        break;
                    case "风速":
                        t2 = validateAndSendData(t1, t2, 0.01, 0, 10000, 16);
                        break;
                    case "功率":
                        t2 = validateAndSendData(t1, t2, 0.01, 0, 10000, 16);
                        break;
                    case "转矩":
                        t2 = validateAndSendData(t1, t2, 0.1, 0, 10000, 16);
                        break;
                    case "发电机转速":
                        t2 = validateAndSendData(t1, t2, 1.0, 0, 2000, 16);
                        break;
                    case "叶轮转速":
                        t2 = validateAndSendData(t1, t2, 0.01, 0, 2000, 16);
                        break;
                    case "风向":
                        t2 = validateAndSendData(t1, t2, 0.1, 0, 3600, 16);
                        break;
                    case "桨距角":
                        t2 = validateAndSendData(t1, t2, 0.1, -100, 1000, 16);
                        break;
                    case "发电量":
                        t2 = validateAndSendData(t1, t2, 1.0, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 32);
                        break;
                    default:
                        LOGGER.warning("Unsupported point: " + t1);// 输出不支持的列头
                        break;
                }
                System.out.println("解析之后的值为：" + t2);
                r += t2;

            }
        }

        return r;

    }


    private static List<String[]> getRedisByKeyNew() {
        List<String[]> data1 = new ArrayList<>();
        for (int i = startNum; i <= startNum+totalNum; i++) {
            String incremented = String.format("%03d", i);
            System.out.println("当前incremented："+incremented);
            String hashKey = "Wec:Jinzixian"+incremented+":TagVal";

            String[] data = new String[10];
            //PLC状态：
            data[0] = new RedisUtil().getHashValue("WecPlcSt");
            //温度：NacOutTmp
            data[1] = new RedisUtil().getHashValue(hashKey,"NacOutTmp");
            //风速：NacWdSpdFltS
            data[2] = new RedisUtil().getHashValue(hashKey,"NacWdSpdFltS");

            //功率：CnvW（有功功率）(float)
            data[3] = new RedisUtil().getHashValue(hashKey,"CnvW");

            //转矩：CnvTorq（转矩）(float)(double)
            data[4] = new RedisUtil().getHashValue(hashKey,"CnvTorq");

            //发电机转速：GenSpd（发电机转速）(float)(int)
            data[5] = new RedisUtil().getHashValue(hashKey,"GenSpd");

            //叶轮转速：RotSpd（风轮转速）(float)
            data[6] = new RedisUtil().getHashValue(hashKey,"RotSpd");

            //风向：NacWdDir（风向）(float)(double)
            data[7] = new RedisUtil().getHashValue(hashKey,"NacWdDir");

            //桨距角
            data[8] = new RedisUtil().getHashValue("PtAngSetBl1");

            //发电量：WecWh（总发电量）(int)
            data[9] = new RedisUtil().getHashValue(hashKey,"WecWh");
            data1.add(data);
            System.out.println("读取key："+hashKey);
            System.out.println("读取key的值结束数量：："+data.length);
        }


        return data1;

    }

    /**
     * 验证并发送数据
     *
     * @param pointName     数据点名称
     * @param pointValueStr 数据点值字符串
     * @param coefficient   系数
     * @param lowerBound    下限
     * @param upperBound    上限
     * @param position      位置
     * @return 处理后的数据点值字符串
     */
    private static String validateAndSendData(String pointName, String pointValueStr, double coefficient, double lowerBound, double upperBound, int position) {
        if (coefficient == 1.0) {
            // 如果系数为1.0
            // 调用int-short-byte方法处理数据点值
            pointValueStr = intshortbyte(pointName, pointValueStr, (int) coefficient, lowerBound, upperBound, position);
        }
        if (coefficient == 0.1) {
            // 如果系数为0.1
            // 调用double-int-short-byte方法处理数据点值
            pointValueStr = doubleintshortbyte(pointName, pointValueStr, coefficient, lowerBound, upperBound, position);
        }
        if (coefficient == 0.01) {
            // 如果系数为0.01
            // 调用float-int-short-byte方法处理数据点值
            pointValueStr = floatintshortbyte(pointName, pointValueStr, (float) coefficient, lowerBound, upperBound, position);
        }
        // 返回处理后的数据点值字符串
        return pointValueStr;
    }


    /**
     * 处理float类型数据点值
     *
     * @param pointName     数据点名称
     * @param pointValueStr 数据点值字符串
     * @param coefficient   系数
     * @param lowerBound    下限
     * @param upperBound    上限
     * @param position      位置
     * @return 处理后的数据点值字符串
     */
    private static String floatintshortbyte(String pointName, String pointValueStr, float coefficient, double lowerBound, double upperBound, int position) {
        try {
            float value = Float.parseFloat(pointValueStr) / coefficient;  // 将数据点值字符串转换为float类型并根据系数进行转换
            LOGGER.info("Range for " + pointName + ": " + lowerBound + " to " + upperBound);  // 记录数据点范围信息
            if (value < lowerBound || value > upperBound) {  // 判断转换后的值是否在范围内
                LOGGER.warning("Value for " + pointName + " out of range: " + pointValueStr);  // 记录数值超出范围的警告信息
                pointValueStr = getTag(position);  // 获取标记值并赋给数据点值字符串
            } else {
                int intValue = (int) value;  // 将float值转换为int
                pointValueStr = inttobyte(intValue, position);  // 调用inttobyte方法处理int值并赋给数据点值字符串
            }
        } catch (NumberFormatException e) {
            LOGGER.warning("Invalid value for " + pointName + ": " + pointValueStr);  // 记录无效数值的警告信息
            pointValueStr = getTag(position);  // 获取标记值并赋给数据点值字符串
        }
        return pointValueStr;  // 返回处理后的数据点值字符串
    }


    /**
     * 获取标记字符串
     *
     * @param count 标记个数
     * @return 标记字符串
     */
    private static String getTag(int count) {
        StringBuilder sb = new StringBuilder();  // 创建StringBuilder对象
        for (int i = 0; i < count; i++) {  // 循环count次
            sb.append("#");  // 在StringBuilder中添加"#"
        }
        String hashString = sb.toString();  // 将StringBuilder转换为字符串
        return hashString;  // 返回标记字符串
    }


    /**
     * 处理double类型数据点值
     *
     * @param pointName     数据点名称
     * @param pointValueStr 数据点值字符串
     * @param coefficient   系数
     * @param lowerBound    下限
     * @param upperBound    上限
     * @param position      位置
     * @return 处理后的数据点值字符串
     */
    private static String doubleintshortbyte(String pointName, String pointValueStr, double coefficient, double lowerBound, double upperBound, int position) {
        try {
            double value = Double.parseDouble(pointValueStr) / coefficient;  // 将数据点值字符串转换为double类型并根据系数进行转换
            LOGGER.info("Range for " + pointName + ": " + lowerBound + " to " + upperBound);  // 记录数据点范围信息
            if (value < lowerBound || value > upperBound) {  // 判断转换后的值是否在范围内
                LOGGER.warning("Value for " + pointName + " out of range: " + pointValueStr);  // 记录数值超出范围的警告信息
                pointValueStr = getTag(position);  // 获取标记值并赋给数据点值字符串
            } else {
                //double doubleValue = 1234.5678;
                int intValue = (int) value;  // 将double值转换为int
                pointValueStr = inttobyte(intValue, position);  // 调用inttobyte方法处理int值并赋给数据点值字符串
            }
        } catch (NumberFormatException e) {
            LOGGER.warning("Invalid value for " + pointName + ": " + pointValueStr);  // 记录无效数值的警告信息
            pointValueStr = getTag(position);  // 获取标记值并赋给数据点值字符串
        }
        return pointValueStr;  // 返回处理后的数据点值字符串
    }


    /**
     * 处理int类型数据点值
     *
     * @param pointName     数据点名称
     * @param pointValueStr 数据点值字符串
     * @param coefficient   系数
     * @param lowerBound    下限
     * @param upperBound    上限
     * @param position      位置
     * @return 处理后的数据点值字符串
     */
    private static String intshortbyte(String pointName, String pointValueStr, int coefficient, double lowerBound, double upperBound, int position) {
        try {
            int value = Integer.parseInt(pointValueStr) / coefficient;  // 将数据点值字符串转换为int类型并根据系数进行转换
            LOGGER.info("Range for " + pointName + ": " + lowerBound + " to " + upperBound);  // 记录数据点范围信息
            if (value < lowerBound || value > upperBound) {  // 判断转换后的值是否在范围内
                LOGGER.warning("Value for " + pointName + " out of range: " + pointValueStr);  // 记录数值超出范围的警告信息
                pointValueStr = getTag(position);  // 获取标记值并赋给数据点值字符串
            } else {
                pointValueStr = inttobyte(value, position);  // 调用inttobyte方法处理int值并赋给数据点值字符串
            }
        } catch (NumberFormatException e) {
            LOGGER.warning("Invalid value for " + pointName + ": " + pointValueStr);  // 记录无效数值的警告信息
            pointValueStr = getTag(position);  // 获取标记值并赋给数据点值字符串
        }
        return pointValueStr;  // 返回处理后的数据点值字符串
    }



    /**
     * 将整数转换为字节串
     *
     * @param number   要转换的整数
     * @param position 二进制串的长度
     * @return 转换后的二进制字符串
     */
    public static String inttobyte(int number, int position) {
        //float->int-short-byte
        // 将整数转换为短整数
        int decimalNumber = number;
        short shortValue = (short) decimalNumber;
        // 将短整数转换为二进制字符串
        String binaryString = Integer.toBinaryString(shortValue);

        // Ensure the binary string is exactly 8 bits (1 byte) long
        // 确保二进制字符串的长度为position
        String paddedBinaryString = String.format("%" + position + "s", binaryString).replace(' ', '0');

        // Print the padded binary representation
        // 打印填充后的二进制表示
        System.out.println("Padded binary representation of " + decimalNumber + " is: " + paddedBinaryString);
        return paddedBinaryString;// 返回填充后的二进制字符串
    }
}
